--- description
-- @module Publc本模块用于一些通用的操作函数
-- @author DengLiLong V1.0 2021/9/15
-- @copyright 2018-2028 Huizhou Govion Technology Ltd. All rights reserved.
-- @usage require("./scripts/public")

enablePrintFlowLog = true;

if(CJSON == nil)then
	CJSON = require("cjson");
end

if gFileHandle == nil then
	gFileHandle = AresFileOp:new();
end

if gLogInfo == nil then
	gLogInfo = LogInfo:new();
end

if gUiMsg == nil then
	gUiMsg = QmlMsg:govionGetObj("luaobj1");
end

--- 格式化打印输出
-- @param ... 不定参数输入
-- @return 输出LOG到调试窗口
function printFlowLog(...)
	if enablePrintFlowLog then
		local datas = "";
		local line = "";
		local itemName = this:getItem().name;
		local time = os.date("%Y-%m-%d %H:%M:%S");
			
		local arg={...}                                 	
    	for i,v in ipairs(arg) do
			local dataType = type(v);	
			if i == 1 then
				line = v;
			elseif dataType == "table" then
				datas = datas..CJSON.encode(v).."\n";
			else 
				datas = datas..tostring(v).."\n";
			end
	    end
	
		print("\n"..time.."["..itemName.."]\t".."Line:"..line.."\n".."msgs:"..datas)
	end
end

--- 获取当前日期
-- @param dateFormat 日期格式,可不填，不填的话按照默认格式输出
-- @return 当前的日期字符串
function getCurrentDate(dateFormat)
	if dateFormat == nil then
		return os.date("%Y%m%d_%H%M%S", os.time());
	else
		return os.date(dateFormat, os.time());
	end
end

--- 获取当前时间
-- @param timeFormat 时间格式,可不填，不填的话按照默认格式输出
-- @return 当前的时间字符串
function getCurrentTime(timeFormat)
	if timeFormat == nil then
		return os.date("%H:%M:%S", os.time());
	else
		return os.date(timeFormat, os.time());
	end
end

--- 获取当前日期时间
-- @param timeFormat 日期时间格式,可不填，不填的话按照默认格式输出
-- @return 当前的日期时间字符串
function getCurrentDateTime(dateTimeFormat)
	if dateTimeFormat == nil then
		return os.date("%Y-%m-%d %H:%M:%S", os.time());
	else
		return os.date(dateTimeFormat, os.time());
	end
end

--- 获取当前精确的日期时间,精确到毫秒
-- @param 无
-- @return 精确的日期时间字符串,如20210909115842.829
function getCurrentAccurateTime()
	return gLogInfo:getTimeMs();
end

--- 发送数据到UI
-- @param functionName UI里的函数名称
-- @param data 传输的数据:可以是字符串,也可以是table,是table的话会自动转换成字符串
-- @return 无
function sendMsgToUi(functionName,data)
	local dataType = type(data);
	if dataType == "string" then
		gUiMsg:setMsg(functionName,data);
	elseif dataType == "table" then
		local msg = CJSON.encode(data);
		gUiMsg:setMsg(functionName,msg);
	end
end

--- 接收UI发送的数据
-- @param timeout 超时时间
-- @return nil 接收超时
-- @return 接收到的字符串数据
-- @see recvMsgObjectFromUi
function recvMsgFromUi(timeout)	
	local msg = gUiMsg:getMsg(timeout);
	if msg == "" then
		return nil;
	else
		return msg;
	end	
end

--- 接收UI发送的数据,并转换成对象
-- @param timeout 超时时间
-- @return nil 接收超时
-- @return 接收到的数据转成对象
-- @see recvMsgFromUi
function recvMsgObjectFromUi(timeout)
	local msg = gUiMsg:getMsg(timeout);
	if msg == "" then
		return nil;
	else
		if false == gFileHandle:isValidJsonString(msg) then
			return nil;
		else
			return CJSON.decode(msg);
		end
	end	
end

--- 发送字符串到其他线程
-- @param thread 目标线程名称
-- @param msg 数据字符串
-- @return true or false
-- @see recvOtherThreadMsg
function sendStringToThread(thread,msg)
	if SubThread:getObj(thread) ~= nil then
		SubThread:getObj(thread):sendMsg(msg);
		return true;
	else
	    print("sendMsgToOtherThread: NO THIS Thread : ",thread);
		return false;
	end
end

--- 将对象转成字符串并发送到其他线程
-- @param thread 目标线程名称
-- @param msgObj 数据对象
-- @return true or false
-- @see recvOtherThreadMsg
function sendObjToThread(thread,msgObj)
	if SubThread:getObj(thread) ~= nil then
		SubThread:getObj(thread):sendMsg(CJSON.encode(msgObj));
		return true;
	else
	    print("sendMsgToOtherThread: NO THIS Thread:",thread);
		return false;
	end
end

--- 判断线程是否存在
-- @param thread 线程名称
-- @return ture or false
function isThreadExist(thread)
	if SubThread:getObj(thread) ~= nil then
		return true;	
	else
		return false;
	end
end

--- 接收并解析其他线程发送的数据
-- @param timeout 超时时间
-- @return nil 当接收超时或者返回的是非法的JSON字符串时
-- @return table 正常时返回解码后的TABLE
-- @see sendMsgToOtherThread
function recvThreadMsgToObj(timeout)
	local message = this:recvMsg(timeout);
	if message == "" then
		return nil;
	end
	
	if false == gFileHandle:isValidJsonString(message) then
		return nil;
	else
		return CJSON.decode(message);
	end
end

--- 将number数据转换成指定位数的小数
-- @param nNum 源数据
-- @param precision 精度
-- @return 转换后的number
function getPreciseDecimal(nNum, precision)
    if type(nNum) ~= "number" then
        return nNum;
    end
    precision = precision or 0;
    precision = math.floor(precision);
    if precision < 0 then
        precision = 0;
    end
    local nDecimal = 10 ^ precision;
    local nTemp = math.floor(nNum * nDecimal);
    local nRet = nTemp / nDecimal;
    return nRet;
end

--- 判断一个字符串是否是有效的json字符串
-- @param strJson 待判断的字符串
-- @return true or false
function isValidJsonString(strJson)
	if type(strJson) ~= "string" then
		return false;
	end 
	
	return gFileHandle:isValidJsonString(strJson);
end

--- 编码table成字符串
-- @param tableObj 编码的对象
-- @return nil(非法输入) 
-- @编码后的字符串(有效输入)
function encode(tableObj)
	if type(tableObj) ~= "table" then
		return nil;
	end
	return CJSON.encode(tableObj);
end

--- 解码字符串成table对象
-- @param strJson 解码的字符串
-- @return nil(非法输入) 
-- @return 解码后的table(有效输入)
function decode(strJson)
	if not gFileHandle:isValidJsonString(strJson) then
		return nil;
	end

	return CJSON.decode(strJson);
end

--- 格式化成可读性更好的json字符串
-- @param strJson 需要格式化的json字符串
-- @return nil(非法输入) 
-- @return 格式化后的json字符串(有效输入)
function formatJson(strJson)
	if not gFileHandle:isValidJsonString(strJson) then
		return nil;
	end

	return gFileHandle:formatJsonString(strJson);
end

--- 格式化字符串
-- @param ... 格式化不定参数
-- @return 格式化后的字符串
function format(...)
	return string.format(...);
end

--- 将输入的字符串按照给定的分割符分割成table
-- @param str 待分割的字符串
-- @param delimiter 分割符
-- @return 分割后的table
function split(str , delimiter)
	local dLen = string.len(delimiter);
    local newDeli = '';
    for i=1,dLen,1 do
        newDeli = newDeli .. "["..string.sub(delimiter, i, i).."]";
    end

    local locaStart,locaEnd = string.find(str, newDeli);
    local arr = {};
    local n = 1;
    while (locaStart ~= nil)
    do
        if (locaStart > 0) then
            arr[n] = string.sub(str, 1, locaStart - 1);
            n = n + 1;
        end

        str = string.sub(str, locaEnd + 1, string.len(str));
        locaStart,locaEnd = string.find(str, newDeli);
    end

    if (str ~= nil) then
        arr[n] = str;
    end
    return arr; 
end

--- 剔除空白字符
-- @param str 待处理的字符串
-- @return 剔除空白字符后的字符串
function trim(str) 
  return (string.gsub(str, "^%s*(.-)%s*$", "%1")) 
end

--- 生成n位的随机字符串
-- @param len 需要生成的随机字符串长度
-- @return 生成的随机字符串
function randomLetter(len)
    local rt = "";
    for i = 1, len, 1 do
		math.randomseed(os.clock()*math.random(1000000,90000000)+math.random(1000000,90000000));
		local tmp =  math.random(97, 122);
        rt = rt..string.char(tmp);
    end
    return rt
end

--- 在一串字符串中查找子串
-- @param srcStr 源字符串
-- @param subStr 子串
-- @return nil(未找到) 
-- @return 开始、结束索引(找到)
-- @usage local startIndex , endIndex = find("Hello" , "l")
function find(srcStr,subStr)
	return string.find(srcStr,subStr);
end

--- 字符串全部转为大写字母
-- @param srcStr 源字符串
-- @return 转换后大写的字符串
function upper(srcStr)
	return string.upper(srcStr);
end

--- 字符串全部转为小写字母
-- @param srcStr 源字符串
-- @Return 转换后小写的字符串
function lower(srcStr)
	return string.lower(srcStr);
end

--- 字符串替换
-- @param mainString 要操作的字符串
-- @param findString 为被替换的字符
-- @param replaceString 要替换的字符
-- @return 替换后的字符串及替换次数
-- @usage local newStr,num=replace("hello","e","o")
function replace(mainString,findString,replaceString)
	return string.gsub(mainString,findString,replaceString);
end

--- 发送日志到日志线程 
-- @param data 需要保存的数据
-- @return 无
-- @see saveFlowLog FileOperation.lua 
function sendLogToLogThread(line,data)
	if (SubThread:getObj("saveLogThread_1") ~= nil) then
		local msg  = {};
		local head = threadName .. ": " .. this:getItem().name .. " " 
						.. "Line[" .. line  .. "]" .. ": " .. "\n";
		msg["Cmd"]  = "SaveFlowLog";
		msg["Head"] = head;
		msg["Data"] = data;
	
		SubThread:getObj("saveLogThread_1"):sendMsg(CJSON.encode(msg));	
	end
end